home *** CD-ROM | disk | FTP | other *** search
/ CDUTIL 13 / CDUTIL #13 Julio 1995.iso / windows / acadcom / ads / sample / colext.c < prev    next >
Encoding:
Text File  |  1995-02-08  |  72.4 KB  |  2,345 lines

  1. /* Next available MSG number is  66 */
  2.  
  3. /*    
  4.  
  5.    COLEXT.C
  6.  
  7.    Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994 by Autodesk, Inc.
  8.  
  9.    Permission to use, copy, modify, and distribute this software in 
  10.    object code form for any purpose and without fee is hereby granted, 
  11.    provided that the above copyright notice appears in all copies and 
  12.    that both that copyright notice and the limited warranty and 
  13.    restricted rights notice below appear in all supporting 
  14.    documentation.
  15.  
  16.    AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
  17.    AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
  18.    MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
  19.    DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
  20.    UNINTERRUPTED OR ERROR FREE.
  21.  
  22.    Use, duplication, or disclosure by the U.S. Government is subject to 
  23.    restrictions set forth in FAR 52.227-19 (Commercial Computer 
  24.    Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
  25.    (Rights in Technical Data and Computer Software), as applicable.
  26.     
  27.    .
  28.  
  29.       DESCRIPTION:
  30.  
  31.         AutoCAD colour manipulation functions
  32.  
  33.         Designed and implemented in October of 1989 by John Walker
  34.  
  35.         This ADS application permits AutoCAD colours to  be  specified
  36.         in  any  of  a  number  of  commonly-used colour systems.  The
  37.         application provides AutoLisp functions for each colour system
  38.         which  accept  the  parameters  which  define a colour in that
  39.         system and return the AutoCAD colour number from the  standard
  40.         palette  for  256  colour  devices which best approximates the
  41.         requested colour.
  42.  
  43.         In  addition, functions are provided to convert either AutoCAD
  44.         colour indices  or  Red-Green-Blue  colour  triples  to  their
  45.         representation in each of the colour systems.
  46.  
  47.         Finally, functions which convert  colours  in  non-RGB  colour
  48.         systems to RGB triples are provided.
  49.  
  50.  
  51.         COLOUR SYSTEMS
  52.         ==============
  53.  
  54.         The colour systems implemented are:
  55.  
  56.         RGB      Colours  are  specified  as the  intensities  of  the
  57.                  three  additive  primary colours Red, Green, and Blue
  58.                  which generate the colour.  The intensities are given
  59.                  in the range from 0 to 1, with 0 indicating no  light
  60.                  of  that colour and 1 representing maximum intensity.
  61.  
  62.         CMY      Colours  are  specified by  the  intensities  of  the
  63.                  subtractive   primary   colours  Cyan,  Magenta,  and
  64.                  Yellow.  The CMY system is used in composing ink  and
  65.                  toner  mixtures  for  subtractive printing processes.
  66.                  Intensities are specified in the range from 0  to  1,
  67.                  with  0  indicating  none  of  the  specified pigment
  68.                  present and 1 indicating the maximum amount.
  69.  
  70.         YIQ      The  YIQ  system  is  used   to  encode  colours  for
  71.                  television broadcasting.  The YIQ system  remaps  the
  72.                  RGB  space such that Y represents a primary scaled to
  73.                  the human luminosity  response  curve.   Two  colours
  74.                  with the same Y values will be indistinguishable when
  75.                  viewed on a monochrome monitor; to guarantee  colours
  76.                  are  distinct  when viewed in monochrome, they should
  77.                  be converted to YIQ and  checked  for  a  substantial
  78.                  difference  in  Y.   Y  ranges from 0 to 1, with zero
  79.                  indicating black and 1 maximum intensity.  Since  the
  80.                  YIQ system is a remapping of the RGB colour cube by a
  81.                  nontrivial affine transformation, the I and Q  values
  82.                  in  the  YIQ  system do not "come out even"; I ranges
  83.                  from -0.6 to 0.6, and Q ranges from  -0.52  to  0.52.
  84.  
  85.         HSV      The HSV system approximates the intuitive concepts of
  86.                  hue  (tint),  saturation  (shade), and value (tone or
  87.                  brightness), by mapping colours into a hexcone.   Hue
  88.                  is  specified  by  a number from 0 to 1, representing
  89.                  the  angle  around  the hue circle in fraction of the
  90.                  circumference of the hue wheel with red at 0,  yellow
  91.                  at  1/6,  and  so  on.   Saturation is expressed as a
  92.                  number from 0 to  1,  with  0  indicating  a  totally
  93.                  desaturated  shade  (grey  scale), and 1 a completely
  94.                  saturated  shade  (no  admixture  of  white).   Value
  95.                  expresses intensity from 0 to 1, with zero indicating
  96.                  black and 1 maximum intensity.
  97.  
  98.         HLS      The  HLS system encodes the intuitive concepts of hue
  99.                  (tint),   lightness   (intensity),   and   saturation
  100.                  (shade), by mapping colours into  a  double  hexcone.
  101.                  The  HLS system is closely related to the HSV system,
  102.                  and can be thought of as the result of stretching the
  103.                  flat   end   of   the  HSV  hexcone  upward  until  a
  104.                  symmetrical   double   hexcone  is  formed.   Hue  is
  105.                  specified by a number from 0 to 1,  representing  the
  106.                  angle  around  the  hue  circle  in  fraction  of the
  107.                  circumference of the hue wheel with red at 0,  yellow
  108.                  at  1/6, and so on.  Lightness expresses intensity as
  109.                  a number from 0 to 1, with zero indicating black  and
  110.                  1  maximum  intensity.   Saturation is expressed as a
  111.                  number from 0 to  1,  with  0  indicating  a  totally
  112.                  desaturated  shade  (grey  scale), and 1 a completely
  113.                  saturated shade (no admixture of white).
  114.  
  115.         CTEMP    The  CTEMP  system  specifies  colours  emitted  by a
  116.                  Planckian  (black  body)  radiator   with   a   given
  117.                  temperature   in   degrees  Kelvin.   Typical  colour
  118.                  temperatures are:
  119.  
  120.                     The star Spica                  28000 K
  121.                     The star Sirius                 10700 K
  122.                     North sky light                  7500 K
  123.                     Average daylight                 6500 K
  124.                     Xenon lamp                       6000 K
  125.                     Typical sunlight + skylight      5500 K
  126.                     The star Betelgeuse              3400 K
  127.                     Tungsten/halogen lamps           3300 K
  128.                     Incandescent bulbs (100-200 W)   2900 K
  129.                     Sunlight at sunset               2000 K
  130.                     Candle flame                     1900 K
  131.  
  132.         CNS      The CNS system expresses colours as English language
  133.                  names.
  134.  
  135.                  A colour is specified in the CNS system by a sequence
  136.                  of  English  words.   CNS  colours  may be achromatic
  137.                  (grey scale values) or chromatic.  Chromatic  colours
  138.                  consist  of  a  hue  (dominant  spectral  component),
  139.                  saturation (the extent of dilution with  white),  and
  140.                  lightness  (intensity).   A chromatic hue is composed
  141.                  by naming and mixing the following primary hues:
  142.  
  143.                     Red, Orange/Brown, Yellow, Green, Blue, Purple
  144.  
  145.                  and secondary hues:
  146.  
  147.                     Reddish, Orangish/Brownish, Yellowish,
  148.                     Greenish, Bluish, Purplish
  149.  
  150.                  To  obtain  one of the primary hues, just specify its
  151.                  name,  e.g.   "Yellow".   To  obtain  a  hue  halfway
  152.                  between  two  primary  hues, compose the two bounding
  153.                  hues: for example "Yellow-green" (or  "Green-yellow";
  154.                  it  doesn't  matter  which  is  specified first).  To
  155.                  obtain a hue one quarter the distance from one colour
  156.                  to  an adjacent colour, compose the "ish" form of the
  157.                  adjacent  colour  with  the  primary   colour.    For
  158.                  example, the hues between Yellow and Green are named:
  159.  
  160.                     Yellow
  161.                     Greenish yellow
  162.                     Yellow-green (or Green-yellow)
  163.                     Yellowish green
  164.                     Green
  165.  
  166.                  Brown  is  a  somewhat  confusing  special case.  The
  167.                  colour we perceive as  brown  has  the  same  hue  as
  168.                  orange  but  when  seen  with  reduced saturation and
  169.                  intensity it appears as brown, a colour distinct from
  170.                  orange  (that's  why there's no brown in the rainbow,
  171.                  in case you've ever lost sleep pondering that  fact).
  172.                  To  compensate for this perceptual quirk, "brown" and
  173.                  "brownish" may be used as synonyms for  "orange"  and
  174.                  "orangish"  when  specifying  hues.   If  "brown"  or
  175.                  "brownish"  are  used,  the  default  saturation  and
  176.                  lightness  (see  below)  are  set  so  the orange hue
  177.                  appears brown; if explicit saturation  and  lightness
  178.                  are given orange and brown are synonymous.
  179.  
  180.                  Lightness  (brightness or intensity) may be specified
  181.                  by adding one of  the  following  adjectives  to  the
  182.                  colour name:
  183.  
  184.                     very dark
  185.                     dark
  186.                     medium
  187.                     light
  188.                     very light
  189.  
  190.                  If  no  lightness  adjective  appears,  a  default is
  191.                  assumed (unless a brown hue was named, in which  case
  192.                  the default will be "light").  This diverges from the
  193.                  CNS specification in which omitted lightness defaults
  194.                  to medium intensity.
  195.  
  196.                  Saturation (the degree of admixture of  white  light)
  197.                  is specified by the following adjectives:
  198.  
  199.                     grayish (or greyish)
  200.                     moderate
  201.                     strong
  202.                     vivid
  203.  
  204.                  "Vivid" denotes a fully saturated colour, and is  the
  205.                  default  (unless  a brown is specified, in which case
  206.                  the default saturation is "strong").
  207.  
  208.                  Examples of chromatic colour specifications are:
  209.  
  210.                     red
  211.                     blue-green
  212.                     purplish red
  213.                     very dark green
  214.                     strong yellow-green
  215.                     very light grayish greenish yellow
  216.  
  217.                  the last  describing  the  colour  of  snow  I  don't
  218.                  recommend you eat.
  219.  
  220.                  Achromatic  specifications describe 7 shades of grey,
  221.                  to wit:
  222.  
  223.                     black
  224.                     very dark gray
  225.                     dark gray
  226.                     gray (or medium gray)
  227.                     light gray
  228.                     very light gray
  229.                     white
  230.  
  231.                  in all cases "grey" may be used instead of "gray".
  232.  
  233.                  Although the word order used herein is as  prescribed
  234.                  by the formal specification of CNS, my implementation
  235.                  is  totally  insensitive  to  word  order.   You  can
  236.                  specify  "yellow  greyish light greenish very" if you
  237.                  like, silly seems how notwithstanding it.
  238.  
  239.  
  240.         AUTOLISP-CALLABLE FUNCTIONS
  241.         ===========================
  242.  
  243.         Three groups of AutoLisp-callable functions  are  implemented.
  244.         The first convert specifications in external colour systems to
  245.         AutoCAD's internal colour indices.  These  functions  map  the
  246.         specifications  into either AutoCAD's standard 8 or 256 colour
  247.         palette.  The palette is selected with the (COLSET) function:
  248.  
  249.            (COLSET <gamut>)
  250.  
  251.         where  <gamut>  is  either  8  or 256 to choose the colour set
  252.         desired.  (COLSET) returns the current colour gamut; if called
  253.         with  no  arguments, (COLSET) returns the current colour gamut
  254.         without changing it.  The following functions  return  AutoCAD
  255.         colour indices between 1 and <gamut> - 1.
  256.  
  257.            (CMY   <cyan> <magenta> <yellow>)
  258.            (CMY '(<cyan> <magenta> <yellow>))
  259.  
  260.            (CNS "CNS colour name description")
  261.  
  262.            (CTEMP <temperature>)
  263.  
  264.            (HLS   <hue> <lightness> <saturation>)
  265.            (HLS '(<hue> <lightness> <saturation>))
  266.  
  267.            (HSV   <hue> <saturation> <value>)
  268.            (HSV '(<hue> <saturation> <value>))
  269.  
  270.            (RGB   <red> <green> <blue>)
  271.            (RGB '(<<red> <green> <blue>))
  272.  
  273.            (YIQ   <Y-value> <I-value> <Q-value>)
  274.            (YIQ '(<Y-value> <I-value> <Q-value>))
  275.  
  276.         Except for the (CNS) function, which takes a string  argument,
  277.         and  (CTEMP)  which  takes  a  single numeric temperature, all
  278.         these  conversion  functions  accept  either  three  numerical
  279.         arguments  (either  integer  or  real),  or  a  list  of three
  280.         numbers.  Representing colour triples as lists,  in  the  same
  281.         manner as three-dimensional point co-ordinates, allows them to
  282.         be manipulated  as  units  and  operated  upon  with  AutoLisp
  283.         functions.  For example the (distance) function can be used to
  284.         determine distance in colour space  as  well  as  in  physical
  285.         space.  If invalid arguments are passed to these functions, an
  286.         error message is displayed and nil  is  returned.   The  (CNS)
  287.         function,  which can generate a wide variety of error messages
  288.         resulting from syntax errors  in  the  string  passed  to  it,
  289.         indicates  an error by returning nil.  A string describing the
  290.         most recent error  detected  by  the  (CNS)  function  can  be
  291.         obtained  by  calling (CNSERR).  If no error has been detected
  292.         by (CNS), (CNSERR) returns nil.
  293.  
  294.         When passed valid arguments, all  of  these  functions  return
  295.         AutoCAD  colour  numbers  ranging  from  1  to  255.  They may
  296.         therefore be specified at any AutoCAD prompt which requests  a
  297.         colour number.
  298.  
  299.         A   second   group   of  functions  converts  external  colour
  300.         specifications to lists of RGB  intensities.   Each  of  these
  301.         functions  takes  the  same  arguments  as the functions which
  302.         return AutoCAD colour indices.
  303.  
  304.            (CMY-RGB   <cyan> <magenta> <yellow>)
  305.            (CMY-RGB '(<cyan> <magenta> <yellow>))
  306.  
  307.            (CNS-RGB "CNS colour name description")
  308.  
  309.            (CTEMP-RGB <temperature>)
  310.  
  311.            (HLS-RGB   <hue> <lightness> <saturation>)
  312.            (HLS-RGB '(<hue> <lightness> <saturation>))
  313.  
  314.            (HSV-RGB   <hue> <saturation> <value>)
  315.            (HSV-RGB '(<hue> <saturation> <value>))
  316.  
  317.            (YIQ-RGB   <Y-value> <I-value> <Q-value>)
  318.            (YIQ-RGB '(<Y-value> <I-value> <Q-value>))
  319.  
  320.         There  is  no RGB-RGB function; it would be simply an identity
  321.         function.
  322.  
  323.         The  third family of functions converts AutoCAD colour indices
  324.         from 0 to 255 or RGB triples to their representation  in  each
  325.         of  the  external  colour  systems.   AutoCAD  colour  index 0
  326.         (black), which cannot be specified as  an  entity  colour,  is
  327.         nonetheless a valid argument to these functions.
  328.  
  329.            (TO-CMY <colour>)
  330.            (TO-CNS <colour>)
  331.            (TO-HLS <colour>)
  332.            (TO-HSV <colour>)
  333.            (TO-RGB <colour>)
  334.            (TO-YIQ <colour>)
  335.  
  336.         With  the  exception  of  (TO-CNS), which returns a CNS colour
  337.         specification string, all of these functions return a list  of
  338.         three  real numbers specifying the values in its colour system
  339.         corresponding to the AutoCAD colour index or RGB  triple.   If
  340.         an  RGB  triple  is  specified for <colour> it may be given as
  341.         three arguments or as a list of three numbers.
  342.  
  343.  
  344.         INTERNAL FUNCTIONS
  345.         ==================
  346.  
  347.         Internal conversion functions implemented in this  module  are
  348.         as  described  below.  Definitions are given as prototypes for
  349.         readability;  for  compatibility  with  older  compilers,  the
  350.         actual  code  is  not  prototyped.  All conversions are to and
  351.         from RGB--to get between two non-RGB systems, you must convert
  352.         through RGB.
  353.  
  354.                                 CMY
  355.  
  356.         void rgb_cmy(ads_real r, ads_real g, ads_real b,
  357.                      ads_real *c, ads_real *m, ads_real *y)
  358.            Converts r, g, b (0 to 1) to c, m, y (0 to 1).
  359.  
  360.         void cmy_rgb(ads_real c, ads_real m, ads_real y,
  361.                      ads_real *r, ads_real *g, ads_real *b)
  362.            Converts c, m, y (0 to 1) to r, g, b (0 to 1).
  363.  
  364.                                CTEMP
  365.  
  366.         void ctemp_rgb(ads_real temperature,
  367.                        ads_real *r, ads_real *g, ads_real *b)
  368.            Converts a colour temperature specified in degrees Kelvin,
  369.            to r, g, b (0 to 1).
  370.  
  371.                                 YIQ
  372.  
  373.         void rgb_yiq(ads_real r, ads_real g, ads_real b,
  374.                      ads_real *y, ads_real *i, ads_real *q)
  375.            Converts r, g, b (0 to 1) to y (0 to 1), i (-0.6 to 0.6),
  376.            and q (-0.52 to 0.52).
  377.  
  378.         void yiq_rgb(ads_real y, ads_real i, ads_real q,
  379.                      ads_real *r, ads_real *g, ads_real *b)
  380.            Converts y (0 to 1), i (-0.6 to 0.6), and q (-0.52 to 0.52)
  381.            to r, g, b (0 to 1).
  382.  
  383.                                 HSV
  384.  
  385.         void rgb_hsv(ads_real r, ads_real g, ads_real b,
  386.                      ads_real *h, ads_real *s, ads_real *v)
  387.            Converts r, g, b (0 to 1) to h (0 to 360), s (0 to 1),  and
  388.            v  (0  to  1).  Note that rgb_hsv() returns hue in terms of
  389.            degrees, not as a  fraction  of  circumference  as  do  the
  390.            AutoLisp-callable functions.
  391.  
  392.         void hsv_rgb(ads_real h, ads_real s, ads_real v,
  393.                      ads_real *r, ads_real *g, ads_real *b)
  394.            Converts  h (0 to 360), s (0 to 1), and v (0 to 1) to r, g,
  395.            b (0 to 1).  Note that rgb_hsv() expects hue  in  terms  of
  396.            degrees,  not  as  a  fraction  of  circumference as do the
  397.            AutoLisp-callable functions.
  398.  
  399.                                 HLS
  400.  
  401.         void rgb_hls(ads_real r, ads_real g, ads_real b,
  402.                      ads_real *h, ads_real *l, ads_real *s)
  403.            Converts r, g, b (0 to 1) to h (0 to 360), l (0 to 1),  and
  404.            s  (0  to  1).  Note that rgb_hls() returns hue in terms of
  405.            degrees, not as a  fraction  of  circumference  as  do  the
  406.            AutoLisp-callable functions.
  407.  
  408.         void hls_rgb(ads_real h, ads_real l, ads_real s,
  409.                      ads_real *r, ads_real *g, ads_real *b)
  410.            Converts  h (0 to 360), l (0 to 1), and s (0 to 1) to r, g,
  411.            b (0 to 1).  Note that rgb_hls() expects hue  in  terms  of
  412.            degrees,  not  as  a  fraction  of  circumference as do the
  413.            AutoLisp-callable functions.
  414.  
  415.                                 CNS
  416.  
  417.         void rgb_cns(ads_real r, ads_real g, ads_real b, char *cnstr)
  418.            Edits  a  zero-terminated  CNS  description  of  the colour
  419.            represented by r, g, and b (0 to 1), into the string cnstr.
  420.            The  maximum  length of the edited string is 36 characters,
  421.            so a buffer of at least 37 characters  should  be  supplied
  422.            for  cnstr.   If  the lightness of the colour is closest to
  423.            the CNS nomenclature for the default  lightness  stored  in
  424.            the  scaled  integer  variable  defcnslit (initially 10000,
  425.            representing 1),  no  intensity  is  edited.   The  default
  426.            saturation of "vivid" is not edited.
  427.  
  428.         Boolean cns_rgb(char *cns, ads_real *r, ads_real *g, ads_real *b)
  429.            Scans  a CNS specification in the string cns and stores RGB
  430.            intensities in r, g, and b which range from 0 to 1.  If  no
  431.            lightness  is  specified, the lightness (as defined for the
  432.            HSV routines) in the  scaled  integer  defcnslit  is  used.
  433.            This  value  is  initially  set  to  10000  for  a  default
  434.            intensity of very light (maximum).  The function returns  1
  435.            if  the  specification  is  valid and 0 if an incorrect CNS
  436.            specification is supplied,  in  which  case  the  character
  437.            pointer  cnserr  will  point to an error message describing
  438.            the problem.
  439.  
  440.         BIBLIOGRAPHY
  441.         ============
  442.  
  443.            Fundamentals of Interactive Computer Graphics
  444.               by J. D. Foley and A. van Dam, Reading Massachusetts:
  445.               Addison-Wesley, 1984.
  446.  
  447.            Measuring Colour
  448.               by R. W. G. Hunt, West Sussex England: Ellis Horwood
  449.               Ltd., 1987.  (Distributed by John Wiley & Sons).
  450.  
  451.            A New Color-Naming System for Graphics Languages
  452.               by Toby Berk, Lee Brownston, and Arie  Kaufman,  Florida
  453.               International  University,  IEEE  Computer  Graphics and
  454.               Applications, May 1982, Page 37.
  455.  
  456. */
  457.  
  458. #include   <stdio.h>
  459. #include   <string.h>
  460. #include   <ctype.h>
  461. #include   <math.h>
  462.  
  463. #include   "adslib.h"
  464.  
  465. #ifdef lint
  466. extern char *sprintf();               /* Adjust for Sun's strange stdio.h */
  467. #endif
  468.  
  469. /* Special assertion handler for ADS applications. */
  470.  
  471. #ifndef NDEBUG
  472. #define assert(ex) {if (!(ex)){ads_printf( \
  473.                     /*MSG1*/"COLEXT: Assertion (%s) failed: file \"%s\", \
  474.                     line %d\n", /*MSG0*/" "#ex" ",__FILE__,__LINE__); \
  475.                     ads_abort(/*MSG2*/"Assertion failed.");}}
  476. #else
  477. #define assert(ex)
  478. #endif
  479.  
  480. /*  Data types  */
  481.  
  482. typedef enum {False = 0, True = 1} Boolean;
  483. #define V        (void)
  484.  
  485. /* Set point variable from three co-ordinates */
  486.  
  487. #define Spoint(pt, x, y, z)  pt[X] = (x);  pt[Y] = (y);  pt[Z] = (z)
  488.  
  489. /* Copy point  */
  490.  
  491. #define Cpoint(d, s)   d[X] = s[X];  d[Y] = s[Y];  d[Z] = s[Z]
  492.  
  493. /* Utility definition to get an  array's  element  count  (at  compile
  494.    time).   For  example:  
  495.  
  496.        int  arr[] = {1,2,3,4,5};
  497.        ... 
  498.        printf("%d", ELEMENTS(arr));
  499.  
  500.    would print a five.  ELEMENTS("abc") can also be used to  tell  how
  501.    many  bytes are in a string constant INCLUDING THE TRAILING NULL. */
  502.  
  503. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  504.  
  505. /* Utility definitions */
  506.  
  507. #ifdef abs
  508. #undef abs
  509. #endif
  510. #define abs(x)      ((x)<0 ? -(x) : (x))
  511. #ifdef min
  512. #undef  min
  513. #endif
  514. #define min(a,b)    ((a)<(b) ? (a) : (b))
  515. #ifdef max
  516. #undef  max
  517. #endif
  518. #define max(a,b)    ((a)>(b) ? (a) : (b))
  519.  
  520. #ifndef M_E
  521. #define M_E     2.7182818284590452354
  522. #endif
  523.  
  524. #define Tbit(x)  (tok & (1L << ((int) (x))))  /* Test token bit set */
  525. #define Tb(x)    (1L << ((int) (x)))  /* Obtain bit to test */
  526.  
  527. /* AutoCAD standard color palette */
  528.  
  529. #define         BLACK           0
  530. #define         RED             1
  531. #define         YELLOW          2
  532. #define         GREEN           3
  533. #define         CYAN            4
  534. #define         BLUE            5
  535. #define         MAGENTA         6
  536. #define         WHITE           7
  537.  
  538. #define         SAT             1.0
  539.  
  540. struct r_g_b {                        /* RGB colour description */
  541.         ads_real red, green, blue;
  542. };
  543.  
  544. /*  Colour naming system vocabulary definition.  The vocabulary
  545.     is defined in this somewhat unusal fashion to facilitate
  546.     translation to languages other than English. */
  547.  
  548. typedef enum {
  549.         /* Chromatic colours */
  550.         Red, Orange, Brown, Yellow, Green, Blue, Purple,
  551.  
  552.         /* "ish" forms of chromatic colours */
  553.         Reddish, Orangish, Brownish, Yellowish, Greenish, Bluish, Purplish,
  554.  
  555.         /* Achromatic names */
  556.         Gray, Black, White,
  557.  
  558.         /* Lightness specifications */
  559.         Very, Dark, Medium, Light,
  560.  
  561.         /* Saturation specifications */
  562.         Grayish, Moderate, Strong, Vivid,
  563.  
  564.         /* Punctuation */
  565.         Hyphen, Period, Huh
  566.        } colourvocab;
  567.  
  568. static struct {
  569.         char *cname;
  570.         colourvocab ccode;
  571. } cvocab[] = {
  572.         {/*MSG3*/"red", Red},
  573.         {/*MSG4*/"orange", Orange},
  574.         {/*MSG5*/"brown", Brown},
  575.         {/*MSG6*/"yellow", Yellow},
  576.         {/*MSG7*/"green", Green},
  577.         {/*MSG8*/"blue", Blue},
  578.         {/*MSG9*/"purple", Purple},
  579.  
  580.         {/*MSG10*/"reddish", Reddish},
  581.         {/*MSG11*/"orangish", Orangish},
  582.         {/*MSG12*/"brownish", Brownish},
  583.         {/*MSG13*/"yellowish", Yellowish},
  584.         {/*MSG14*/"greenish", Greenish},
  585.         {/*MSG15*/"bluish", Bluish},
  586.         {/*MSG16*/"purplish", Purplish},
  587.  
  588.         {/*MSG17*/"gray", Gray},
  589.         {/*MSG18*/"grey", Gray},
  590.         {/*MSG19*/"black", Black},
  591.         {/*MSG20*/"white", White},
  592.  
  593.         {/*MSG21*/"very", Very},
  594.         {/*MSG22*/"dark", Dark},
  595.         {/*MSG23*/"medium", Medium},
  596.         {/*MSG24*/"light", Light},
  597.  
  598.         {/*MSG25*/"grayish", Grayish},
  599.         {/*MSG26*/"greyish", Grayish},
  600.         {/*MSG27*/"moderate", Moderate},
  601.         {/*MSG28*/"strong", Strong},
  602.         {/*MSG29*/"vivid", Vivid}
  603.        };
  604.  
  605. /* Table mapping generic hues to HSV hue indices. */
  606.  
  607. static struct {
  608.         long cbit;
  609.         int chue;
  610. } colhue[] = {
  611.         {Tb(Red),      0},            /* red */
  612.         {Tb(Orange),  30},            /* orange */
  613.         {Tb(Brown),  -30},            /* brown */
  614.         {Tb(Yellow),  60},            /* yellow */
  615.         {Tb(Green),  120},            /* green */
  616.         {Tb(Blue),   240},            /* blue */
  617.         {Tb(Purple), 300},            /* purple */
  618.         {0L,         360}             /* red (other incarnation) */
  619.        };
  620.  
  621. /* Table mapping secondary hues to HSV hue indices. */
  622.  
  623. static struct {
  624.         long cbit;
  625.         int chue;
  626. } ishhue[] = {
  627.         {Tb(Reddish),      0},        /* reddish */
  628.         {Tb(Orangish),    30},        /* orangish */
  629.         {Tb(Brownish),   -30},        /* brownish */
  630.         {Tb(Yellowish),   60},        /* yellowish */
  631.         {Tb(Greenish),   120},        /* greenish */
  632.         {Tb(Bluish),     240},        /* bluish */
  633.         {Tb(Purplish),   300},        /* purplish */
  634.         {0L,             360}         /* reddish (other incarnation) */
  635.        };
  636.  
  637. #define MAXTK    10                   /* Maximum tokens in specification */
  638. #define MAXTKS   20                   /* Longest token in characters */
  639.  
  640. #define BROWNLIGHT  3                 /* Brown lightness:  Medium */
  641. #define BROWNSAT    3                 /* Brown saturation: Strong */
  642.  
  643. /* Modal variables  */
  644.  
  645. static int defcnslit = 10000;         /* Default lightness if none specified */
  646. static int gamut = 256;               /* Colour gamut available */
  647.  
  648. /*  Local variables  */
  649.  
  650. static char *cnserr = NULL;           /* Error message string */
  651. static char cnserb[80];               /* Error message edit buffer */
  652. static char tokenb[MAXTKS];           /* Token buffer */
  653.  
  654. /*  Forward functions  */
  655.  
  656. void   main _((int, char **));
  657. void   funcload _((void));
  658. void   hsv_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  659. void   rgb_hsv _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  660. void   rgb_hls _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  661. ads_real hlsval _((ads_real, ads_real, ads_real));
  662. void   hls_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  663. void   rgb_yiq _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  664. void   yiq_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  665. void   rgb_cmy _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  666. void   ctemp_rgb _((ads_real, ads_real *,ads_real *,ads_real *));
  667. #ifdef NEEDED
  668. void   cmy_rgb _((ads_real,ads_real,ads_real,ads_real *,ads_real *,ads_real *));
  669. #endif
  670. colourvocab token _((char **));
  671. Boolean cns_rgb _((char *, ads_real *, ads_real *, ads_real *));
  672. char    *cixname _((colourvocab));
  673. void    rgb_cns _((ads_real, ads_real, ads_real, char *));
  674. void    acadrgb _((int, struct r_g_b *));
  675. int     rgbacad _((ads_real, ads_real, ads_real));
  676. void    retrgb _((Boolean, ads_real, ads_real, ads_real));
  677. Boolean triple _((ads_real *, Boolean));
  678. void    cmy _((Boolean));
  679. void    cns _((Boolean));
  680. void    cnser _((void));
  681. void    ctemp _((Boolean));
  682. void    hls _((Boolean));
  683. void    hsv _((Boolean));
  684. void    rgb _((Boolean));
  685. void    yiq _((Boolean));
  686. void    cmyac _((void));
  687. void    ctempac _((void));
  688. void    yiqac _((void));
  689. void    hsvac _((void));
  690. void    rgbac _((void));
  691. void    hlsac _((void));
  692. void    cnsac _((void));
  693. void    cmyrgb _((void));
  694. void    ctemprgb _((void));
  695. void    yiqrgb _((void));
  696. void    hsvrgb _((void));
  697. void    hlsrgb _((void));
  698. void    cnsrgb _((void));
  699. Boolean acadcol _((struct r_g_b *));
  700. void    torgb _((void));
  701. void    tocmy _((void));
  702. void    toyiq _((void));
  703. void    tohsv _((void));
  704. void    tohls _((void));
  705. void    tocns _((void));
  706. void    colset _((void));
  707.  
  708.  
  709. /*  Command definition and dispatch table.  */
  710.  
  711. struct {
  712.         char *cmdname;
  713.         void (*cmdfunc)();
  714. } cmdtab[] = {
  715. /*        Name         Function  */
  716.  
  717. /* External colour system to AutoCAD colour functions */
  718.  
  719. {/*MSG0*/"CMY",       cmyac},
  720. {/*MSG0*/"CNS",       cnsac},
  721. {/*MSG0*/"CTEMP",     ctempac},
  722. {/*MSG0*/"HLS",       hlsac},
  723. {/*MSG0*/"HSV",       hsvac},
  724. {/*MSG0*/"RGB",       rgbac},
  725. {/*MSG0*/"YIQ",       yiqac},
  726.  
  727. /* External colour system to RGB functions */
  728.  
  729. {/*MSG0*/"CMY-RGB",   cmyrgb},
  730. {/*MSG0*/"CNS-RGB",   cnsrgb},
  731. {/*MSG0*/"CTEMP-RGB", ctemprgb},
  732. {/*MSG0*/"HLS-RGB",   hlsrgb},
  733. {/*MSG0*/"HSV-RGB",   hsvrgb},
  734. {/*MSG0*/"YIQ-RGB",   yiqrgb},
  735.  
  736. /* AutoCAD colour index to external colour system functions */
  737.  
  738. {/*MSG0*/"TO-RGB",    torgb},
  739. {/*MSG0*/"TO-CMY",    tocmy},
  740. {/*MSG0*/"TO-YIQ",    toyiq},
  741. {/*MSG0*/"TO-HSV",    tohsv},
  742. {/*MSG0*/"TO-HLS",    tohls},
  743. {/*MSG0*/"TO-CNS",    tocns},
  744.  
  745. /* Control and utility functions */
  746.  
  747. {/*MSG0*/"CNSERR",    cnser},
  748. {/*MSG0*/"COLSET",    colset}
  749. };
  750.  
  751. /*  MAIN  --  Main ADS dispatch loop.  */
  752.  
  753. void main(argc, argv)
  754.   int argc;
  755.   char *argv[];
  756. {
  757.     int stat, cindex, scode = RSRSLT;
  758.     char errmsg[80];
  759.  
  760.     ads_init(argc, argv);             /* Initialise the application */
  761.  
  762.     /* Main dispatch loop. */
  763.  
  764.     while (True) {
  765.  
  766.         if ((stat = ads_link(scode)) < 0) {
  767.             V sprintf(errmsg,
  768.                       /*MSG30*/"COLEXT: bad status from ads_link() = %d\n",
  769.                       stat);
  770. #ifdef Macintosh
  771.             macalert(errmsg);
  772. #else
  773.             puts(errmsg);
  774.             fflush(stdout);
  775. #endif /* Macintosh */
  776.             exit(1);
  777.         }
  778.  
  779.         scode = RSRSLT;               /* Default return code */
  780.  
  781.         switch (stat) {
  782.  
  783.         case RQXLOAD:                 /* Load functions.  Called at the start
  784.                                                 of the drawing editor.  */
  785.             funcload();
  786.             break;
  787.  
  788.         case RQSUBR:                  /* Evaluate external lisp function */
  789.             cindex = ads_getfuncode();
  790.  
  791.             /* Execute the command from the command table with
  792.                the index associated with this function. */
  793.  
  794.             if (cindex > 0) {
  795.                 cindex--;
  796.                 assert(cindex < ELEMENTS(cmdtab));
  797.                 (*cmdtab[cindex].cmdfunc)();
  798.             }
  799.             break;
  800.  
  801.         default:
  802.             break;
  803.         }
  804.     }
  805. }
  806.  
  807. /* FUNCLOAD  --  Load external functions into AutoLisp.  */
  808.  
  809. static void funcload()
  810. {
  811.     int i;
  812.  
  813.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  814.         ads_defun(cmdtab[i].cmdname, i + 1);
  815.     }
  816. }
  817.  
  818. /*      ***************************************************
  819.         **                                               **
  820.         **       Colour Interconversion Functions        **
  821.         **                                               **
  822.         ***************************************************
  823. */
  824.  
  825. /*  HSV_RGB  --  Convert HSV colour specification to RGB  intensities.
  826.                  Hue is specified as a  real  value  from  0  to  360,
  827.                  Saturation  and  Intensity as reals from 0 to 1.  The
  828.                  RGB components are returned as reals from 0 to 1.      */
  829.  
  830. static void hsv_rgb(h, s, v, r, g, b)
  831.   ads_real h, s, v;
  832.   ads_real *r, *g, *b;
  833. {
  834.     int i;
  835.     ads_real f, p, q, t;
  836.  
  837.     if (s == 0) {
  838.         *r = *g = *b = v;
  839.     } else {
  840.         if (h == 360.0)
  841.             h = 0;
  842.         h /= 60.0;
  843.  
  844.         i = h;
  845.         f = h - i;
  846.         p = v * (1.0 - s);
  847.         q = v * (1.0 - (s * f));
  848.         t = v * (1.0 - (s * (1.0 - f)));
  849.         assert(i >= 0 && i <= 5);
  850.         switch (i) {
  851.  
  852.         case 0:
  853.             *r = v;
  854.             *g = t;
  855.             *b = p;
  856.             break;
  857.  
  858.         case 1:
  859.             *r = q;
  860.             *g = v;
  861.             *b = p;
  862.             break;
  863.  
  864.         case 2:
  865.             *r = p;
  866.             *g = v;
  867.             *b = t;
  868.             break;
  869.  
  870.         case 3:
  871.             *r = p;
  872.             *g = q;
  873.             *b = v;
  874.             break;
  875.  
  876.         case 4:
  877.             *r = t;
  878.             *g = p;
  879.             *b = v;
  880.             break;
  881.  
  882.         case 5:
  883.             *r = v;
  884.             *g = p;
  885.             *b = q;
  886.             break;
  887.         }
  888.     }
  889. }
  890.  
  891. /*  RGB_HSV  --  Map R, G, B intensities in the range from 0 to 1 into
  892.                  Hue, Saturation,  and  Value:  Hue  from  0  to  360,
  893.                  Saturation  from  0  to  1,  and  Value  from 0 to 1.
  894.                  Special case: if Saturation is 0 (it's a  grey  scale
  895.                  tone), Hue is undefined and is returned as -1.
  896.  
  897.                  This follows Foley & van Dam, section 17.4.4.  */
  898.  
  899. static void rgb_hsv(r, g, b, h, s, v)
  900.   ads_real r, g, b;
  901.   ads_real *h, *s, *v;
  902. {
  903.     ads_real imax = max(r, max(g, b)),
  904.              imin = min(r, min(g, b)),
  905.              rc, gc, bc;
  906.  
  907.     *v = imax;
  908.     if (imax != 0)
  909.         *s = (imax - imin) / imax;
  910.     else
  911.         *s = 0;
  912.  
  913.     if (*s == 0) {
  914.         *h = -1;
  915.     } else {
  916.         rc = (imax - r) / (imax - imin);
  917.         gc = (imax - g) / (imax - imin);
  918.         bc = (imax - b) / (imax - imin);
  919.         if (r == imax)
  920.             *h = bc - gc;
  921.         else if (g == imax)
  922.             *h = 2.0 + rc - bc;
  923.         else
  924.             *h = 4.0 + gc - rc;
  925.         *h *= 60.0;
  926.         if (*h < 0.0)
  927.             *h += 360.0;
  928.     }
  929. }
  930.  
  931. /*  RGB_HLS  --  Map R, G, B intensities in the range from 0 to 1 into
  932.                  Hue, Lightness, and Saturation: Hue from  0  to  360,
  933.                  Lightness  from  0  to 1, and Saturation from 0 to 1.
  934.                  Special case: if Saturation is 0 (it's a  grey  scale
  935.                  tone), Hue is undefined and is returned as -1.
  936.  
  937.                  This follows Foley & van Dam, section 17.4.5.  */
  938.  
  939. static void rgb_hls(r, g, b, h, l, s)
  940.   ads_real r, g, b;
  941.   ads_real *h, *l, *s;
  942. {
  943.     ads_real imax = max(r, max(g, b)),
  944.              imin = min(r, min(g, b)),
  945.              rc, gc, bc;
  946.  
  947.     *l = (imax + imin) / 2;
  948.  
  949.     if (imax == imin) {
  950.         *s = 0;
  951.         *h = -1;
  952.     } else {
  953.         if (*l <= 0.5)
  954.             *s = (imax - imin) / (imax + imin);
  955.         else
  956.             *s = (imax - imin) /
  957.                  (2.0 - imax - imin);
  958.  
  959.         rc = (imax - r) / (imax - imin);
  960.         gc = (imax - g) / (imax - imin);
  961.         bc = (imax - b) / (imax - imin);
  962.         if (r == imax)
  963.             *h = bc - gc;
  964.         else if (g == imax)
  965.             *h = 2.0 + rc - bc;
  966.         else
  967.             *h = 4.0 + gc - rc;
  968.         *h *= 60.0;
  969.         if (*h < 0)
  970.             *h += 360.0;
  971.     }
  972. }
  973.  
  974. /*  HLS_RGB  --  Convert HLS colour specification to RGB  intensities.
  975.                  Hue  is  specified  as  a  real  value from 0 to 360;
  976.                  Lightness and Saturation as reals from 0 to  1.   The
  977.                  RGB components are returned as reals from 0 to 1.      */
  978.  
  979. static ads_real hlsval(n1, n2, hue)
  980.   ads_real n1, n2, hue;
  981. {
  982.     if (hue > 360.0)
  983.         hue -= 360.0;
  984.     else if (hue < 0.0)
  985.         hue += 360.0;
  986.     if (hue < 60.0) {
  987.         return n1 + ((n2 - n1) * hue) / 60.0;
  988.     } else if (hue < 180.0) {
  989.         return n2;
  990.     } else if (hue < 240.0) {
  991.         return n1 + ((n2 - n1) * (240.0 - hue)) / 60.0;
  992.     } else {
  993.         return n1;
  994.     }
  995. }
  996.  
  997. static void hls_rgb(h, l, s, r, g, b)
  998.   ads_real h, l, s;
  999.   ads_real *r, *g, *b;
  1000. {
  1001.     ads_real m1, m2;
  1002.  
  1003.     if (l <= 0.5)
  1004.         m2 = l * (1.0 + s);
  1005.     else
  1006.         m2 = l + s - (l * s);
  1007.     m1 = 2 * l - m2;
  1008.  
  1009.     if (s == 0) {
  1010.         *r = *g = *b = l;
  1011.     } else {
  1012.         *r = hlsval(m1, m2, h + 120.0);
  1013.         *g = hlsval(m1, m2, h);
  1014.         *b = hlsval(m1, m2, h - 120.0);
  1015.     }
  1016. }
  1017.  
  1018. /*  RGB_YIQ  --  Convert RGB colour specification, R, G, B ranging
  1019.                  from 0 to 1, to Y, I, Q colour specification.
  1020.  
  1021.                  |Y|   |0.30  0.59  0.11|   |R|
  1022.                  |I| = |0.60 -0.28 -0.32| . |G|
  1023.                  |Q|   |0.21 -0.52  0.31|   |B|
  1024. */
  1025.  
  1026. static void rgb_yiq(r, g, b, y, i, q)
  1027.   ads_real r, g, b;
  1028.   ads_real *y, *i, *q;
  1029. {
  1030.     ads_real ay = (r * 0.30 + g *  0.59 + b *  0.11),
  1031.              ai = (r * 0.60 + g * -0.28 + b * -0.32),
  1032.              aq = (r * 0.21 + g * -0.52 + b *  0.31);
  1033.  
  1034.     *y = ay;
  1035.     if (ay == 1.0) {                  /* Prevent round-off on grey scale */
  1036.         ai = aq = 0.0;
  1037.     }
  1038.     *i = ai;
  1039.     *q = aq;
  1040. }
  1041.  
  1042. /*  YIQ_RGB  --  Convert YIQ colour specification, Y, I,  Q  given  as
  1043.                  reals,  Y  from  0  to  1, I from -0.6 to 0.6, Q from
  1044.                  -0.52 to 0.52, to R, G, B intensities  in  the  range
  1045.                  from  0 to 1.  The matrix below is the inverse of the
  1046.                  RGB_YIQ matrix above.
  1047.  
  1048.                  |R|   |1.00  0.948  0.624|   |Y|
  1049.                  |G| = |1.00 -0.276 -0.640| . |I|
  1050.                  |B|   |1.00 -1.105  1.730|   |Q|
  1051. */
  1052.  
  1053. static void yiq_rgb(y, i, q, r, g, b)
  1054.   ads_real y, i, q;
  1055.   ads_real *r, *g, *b;
  1056. {
  1057.     ads_real ar = (y + i *   0.948 + q *  0.624),
  1058.              ag = (y + i *  -0.276 + q * -0.640),
  1059.              ab = (y + i *  -1.105 + q *  1.730);
  1060.  
  1061.     *r = max(0, min(1.0, ar));
  1062.     *g = max(0, min(1.0, ag));
  1063.     *b = max(0, min(1.0, ab));
  1064. }
  1065.  
  1066. /*  RGB_CMY  --  Convert RGB colour specification,  R,  G,  B  ranging
  1067.                  from  0  to  1, to C, M, Y colour specification, also
  1068.                  ranging from 0 to 1.
  1069.  
  1070.                  |C|   |1|   |R|
  1071.                  |M| = |1| - |G|
  1072.                  |Y|   |1|   |B|
  1073. */
  1074.  
  1075. static void rgb_cmy(r, g, b, c, m, y)
  1076.   ads_real r, g, b;
  1077.   ads_real *c, *m, *y;
  1078. {
  1079.     *c = 1.0 - r;
  1080.     *m = 1.0 - g;
  1081.     *y = 1.0 - b;
  1082. }
  1083.  
  1084. #ifdef NEEDED
  1085.  
  1086. /*  CMY_RGB  --  Convert CMY colour specification,  C,  M,  Y  ranging
  1087.                  from  0  to  1, to R, G, B colour specification, also
  1088.                  ranging from 0 to 1.
  1089.  
  1090.                  |R|   |1|   |C|
  1091.                  |G| = |1| - |M|
  1092.                  |B|   |1|   |Y|
  1093. */
  1094.  
  1095. static void cmy_rgb(c, m, y, r, g, b)
  1096.   ads_real c, m, y;
  1097.   ads_real *r, *g, *b;
  1098. {
  1099.     *r = 1.0 - c;
  1100.     *g = 1.0 - m;
  1101.     *b = 1.0 - y;
  1102. }
  1103. #endif
  1104.  
  1105. /*  CTEMP_RGB  --  Calculate the relative R, G, and B components for a
  1106.                    black body emitting light at a  given  temperature.
  1107.                    The  Planck  radiation  equation is solved directly
  1108.                    for the R, G, and B wavelengths defined for the CIE
  1109.                    1931  Standard  Colorimetric  Observer.  The colour
  1110.                    temperature is specified in degrees Kelvin. */
  1111.  
  1112. static void ctemp_rgb(temp, r, g, b)
  1113.   double temp;
  1114.   double *r, *g, *b;
  1115. {
  1116.     double c1 = 3.74183e10,
  1117.            c2 = 14388.0,
  1118.            er, eg, eb, es;
  1119.  
  1120. /* Lambda is the wavelength in microns: 5500 angstroms is 0.55 microns. */
  1121.  
  1122. #define Planck(lambda)  ((c1 * pow((double) lambda, -5.0)) /  \
  1123.                          (pow(M_E, c2 / (lambda * temp)) - 1))
  1124.  
  1125.     er = Planck(0.7000);
  1126.     eg = Planck(0.5461);
  1127.     eb = Planck(0.4358);
  1128. #undef Planck
  1129.  
  1130.     es = 1.0 / max(er, max(eg, eb));
  1131.  
  1132.     *r = er * es;
  1133.     *g = eg * es;
  1134.     *b = eb * es;
  1135. }
  1136.  
  1137. /*  TOKEN  --  Scan next token from the CNS string and update the
  1138.                scan pointer.  */
  1139.  
  1140. static colourvocab token(icp)
  1141.   char **icp;
  1142. {
  1143.     char ch;
  1144.     char *cp = *icp, *tch;
  1145.     int i, t = 0;
  1146.  
  1147.     /* Ignore leading space */
  1148.  
  1149.     while (True) {
  1150.         ch = *cp++;
  1151.         if (!isspace(ch))
  1152.             break;
  1153.     }
  1154.  
  1155.     if (ch == EOS)
  1156.         return Period;
  1157.  
  1158.     if (ch == '-') {
  1159.         *icp = cp;
  1160.         return Hyphen;
  1161.     }
  1162.  
  1163.     tch = cp - 1;                     /* Start of token pointer */
  1164.     if (!isalpha(ch)) {
  1165.         *cp = EOS;
  1166.         *icp = tch;
  1167.         return Huh;
  1168.     }
  1169.  
  1170.     while (isalpha(ch)) {
  1171.         if (isupper(ch))
  1172.             ch = tolower(ch);
  1173.         if (t < ((sizeof tokenb) - 2))
  1174.             tokenb[t++] = ch;
  1175.         ch = *cp++;
  1176.     }
  1177.     tokenb[t] = EOS;
  1178.     *icp = cp - 1;
  1179.  
  1180.     for (i = 0; i < ELEMENTS(cvocab); i++) {
  1181.         if (strcmp(tokenb, cvocab[i].cname) == 0) {
  1182.             return cvocab[i].ccode;
  1183.         }
  1184.     }
  1185.     **icp = EOS;
  1186.     *icp = tch;
  1187.     return Huh;
  1188. }
  1189.  
  1190. /*  CNS_RGB  --  Convert a CNS string to RGB intensities scaled from 0
  1191.                  to 1.  If an invalid specification is made,  0
  1192.                  is returned and an error message is pointed to by the
  1193.                  global character pointer  cnserr.   Otherwise,  1  is
  1194.                  returned.  */
  1195.  
  1196. static Boolean cns_rgb(cns, r, g, b)
  1197.   char *cns;
  1198.   ads_real *r, *g, *b;
  1199. {
  1200.     int i, j, k = 0, lightness, saturation;
  1201.     long tok = 0L, hue;
  1202.     colourvocab t;
  1203.     static char conflite[] = /*MSG31*/"Conflicting lightness specification.";
  1204.     /* Grey scale table */
  1205.     static int greyscale[] = {50, 17, 33, 50, 67, 83};
  1206.     /* Saturation percentage table */
  1207.     static int satab[] = {10000, 2500, 5000, 7500, 10000};
  1208.     /* Chromatic lightness table */
  1209.     static int litetab[] = {5000, 1300, 2500, 5000, 7500, 10000};
  1210.  
  1211.     cnserr = NULL;                    /* Initially no error in CNS string */
  1212.     j = strlen(cns);
  1213.     if (j == 0) {
  1214.         cnserr = /*MSG32*/"Void specification.";
  1215.         return False;
  1216.     }
  1217.  
  1218.     /* Scan string and parse tokens */
  1219.  
  1220.     while (True) {
  1221.         t = token(&cns);
  1222.         if (t == Huh) {
  1223.             V sprintf(cnserb, /*MSG33*/"Unrecognised symbol: `%s'.", cns);
  1224.             cnserr = cnserb;
  1225.             return False;
  1226.         }
  1227.         if (Tbit(t)) {
  1228.             V sprintf(cnserb, /*MSG34*/"Duplicate symbol: `%s'.", tokenb);
  1229.             cnserr = cnserb;
  1230.             return False;
  1231.         }
  1232.         if (t == Period)
  1233.             break;
  1234.         tok |= 1L << ((int) t);
  1235.     }
  1236.  
  1237.     /* Try to obtain lightness from specification */
  1238.  
  1239.     if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
  1240.         if (Tbit(Medium)) {
  1241.             if (Tbit(Very)) {
  1242.                 cnserr = /*MSG35*/"Very used with Medium.";
  1243.                 return False;
  1244.             }
  1245.             if (Tbit(Light) || Tbit(Dark)) {
  1246.                 cnserr = conflite;
  1247.                 return False;
  1248.             }
  1249.             lightness = 3;
  1250.         } else if (Tbit(Dark)) {
  1251.             lightness = Tbit(Very) ? 1 : 2;
  1252.             if (Tbit(Light)) {
  1253.                 cnserr = conflite;
  1254.                 return False;
  1255.             }
  1256.         } else if (Tbit(Light)) {
  1257.             lightness = Tbit(Very) ? 5 : 4;
  1258.         } else {
  1259.             cnserr = /*MSG36*/"Very used without Light or Dark.";
  1260.             return False;
  1261.         }
  1262.     } else {
  1263.         lightness = 0;
  1264.     }
  1265.  
  1266.     /* Test for achromatic colour specification. */
  1267.  
  1268.     i = !!(Tbit(Black)) + !!(Tbit(Gray)) + !!(Tbit(White));
  1269.     if (i > 0) {
  1270.  
  1271.         /* Test for conflicting specification of more than
  1272.            one achromatic colour. */
  1273.  
  1274.         if (i != 1) {
  1275.             cnserr = /*MSG37*/"Conflicting black/gray/white specification.";
  1276.             return False;
  1277.         }
  1278.  
  1279.         /* Test for specification of chromatic colour with
  1280.            achromatic colour. */
  1281.  
  1282.         if (tok & (Tb(Red) | Tb(Orange) | Tb(Brown) | Tb(Yellow) |
  1283.                    Tb(Green) | Tb(Blue) | Tb(Purple))) {
  1284.             cnserr = /*MSG38*/"Chromatic and achromatic shade mixed.";
  1285.             return False;
  1286.         }
  1287.  
  1288.         /* Test for specification of chromatic colour ish form with
  1289.            achromatic colour. */
  1290.  
  1291.         if (tok & (Tb(Reddish) | Tb(Orangish) |
  1292.                    Tb(Brownish) | Tb(Yellowish) |
  1293.                    Tb(Greenish) | Tb(Bluish) | Tb(Purplish) |
  1294.                    Tb(Hyphen))) {
  1295.             cnserr = /*MSG39*/"Chromatic modifier and achromatic shade mixed.";
  1296.             return False;
  1297.         }
  1298.  
  1299.         /* Test for saturation specification with achromatic shade. */
  1300.  
  1301.         if (tok & (Tb(Grayish) | Tb(Moderate) | Tb(Strong) | Tb(Vivid))) {
  1302.             cnserr = /*MSG40*/"Saturation specified with achromatic shade.";
  1303.             return False;
  1304.         }
  1305.  
  1306.         /* Test for lightness specified with White or Black. */
  1307.  
  1308.         if (Tbit(White) || Tbit(Black)) {
  1309.             if (tok & (Tb(Very) | Tb(Dark) | Tb(Medium) | Tb(Light))) {
  1310.                 cnserr = /*MSG41*/"Lightness specified with black or white.";
  1311.                 return False;
  1312.             }
  1313.             if (Tbit(White)) {
  1314.                 *r = *g = *b = 1.0;   /* White */
  1315.             } else {
  1316.                 *r = *g = *b = 0;     /* Black */
  1317.             }
  1318.             return True;
  1319.         }
  1320.  
  1321.         /* Calculate grey scale value from lightness specification. */
  1322.  
  1323.         *r = *g = *b = greyscale[lightness] / 100.0;
  1324.         return True;
  1325.     }
  1326.  
  1327.     /* It isn't a grey scale, so it must be a chromatic colour
  1328.        specification.  Before we tear into the hue, let's try and
  1329.        determine the saturation. */
  1330.  
  1331.     i = (!!Tbit(Grayish)) + (!!Tbit(Moderate)) +
  1332.         (!!Tbit(Strong)) + (!!Tbit(Vivid));
  1333.     if (i > 0) {
  1334.         if (i > 1) {
  1335.             cnserr = /*MSG42*/"Conflicting saturation specification.";
  1336.             return False;
  1337.         }
  1338.         saturation = Tbit(Grayish) ? 1 :
  1339.                      (Tbit(Moderate) ? 2 :
  1340.                       (Tbit(Strong) ? 3 : 4));
  1341.     } else {
  1342.         saturation = 0;
  1343.     }
  1344.  
  1345.     /* Count primary hue specifications. */
  1346.  
  1347.     i = (!!Tbit(Red)) + (!!Tbit(Orange)) + (!!Tbit(Brown)) +
  1348.         (!!Tbit(Yellow)) +
  1349.         (!!Tbit(Green)) + (!!Tbit(Blue)) + (!!Tbit(Purple));
  1350.  
  1351.     if (i == 0) {
  1352.         cnserr = /*MSG43*/"No hue specified.";
  1353.         return False;
  1354.     }
  1355.     if (i > 2) {
  1356.         cnserr = /*MSG44*/"More than two hues specified.";
  1357.         return False;
  1358.     }
  1359.  
  1360.     /* Count secondary hue specifications. */
  1361.  
  1362.     j = (!!Tbit(Reddish)) + (!!Tbit(Orangish)) + (!!Tbit(Brownish)) +
  1363.         (!!Tbit(Yellowish)) +
  1364.         (!!Tbit(Greenish)) + (!!Tbit(Bluish)) + (!!Tbit(Purplish));
  1365.  
  1366.     if (j > 1) {
  1367.         cnserr = /*MSG45*/"More than one secondary hue specified.";
  1368.         return False;
  1369.     }
  1370.     if (i == 2 && j > 0) {
  1371.         cnserr = /*MSG46*/"Secondary hue specified with two primary hues.";
  1372.         return False;
  1373.     }
  1374.  
  1375.     /* Obtain hue based on form of specification we've determined
  1376.        is being made.
  1377.  
  1378.        Case 1.  Pure hue specified by a single primary hue. */
  1379.  
  1380.     hue = -1;
  1381.     if (i == 1 && j == 0) {
  1382.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1383.             if (tok & colhue[i].cbit) {
  1384.                 hue = abs(colhue[i].chue) * 100L;
  1385.                 /* If it's brown, impute saturation and lightness
  1386.                    if none was explicitly specified. */
  1387.                 if (colhue[i].chue < 0) {
  1388.                     if (lightness == 0)
  1389.                         lightness = BROWNLIGHT;
  1390.                     if (saturation == 0)
  1391.                         saturation = BROWNSAT;
  1392.                 }
  1393.                 break;
  1394.             }
  1395.         }
  1396.     } else if (i == 2) {
  1397.  
  1398.         /* Case 2.  Halfway hue specified by composing two adjacent
  1399.                     primary hues. */
  1400.  
  1401.         j = k = -1;
  1402.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1403.             if (tok & colhue[i].cbit) {
  1404.                 if (j < 0)
  1405.                     j = i;
  1406.                 else {
  1407.                     k = i;
  1408.                     break;
  1409.                 }
  1410.             }
  1411.         }
  1412.         if ((colhue[j].chue == -colhue[k].chue) ||
  1413.             (((j + 1) != k) &&
  1414.              !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
  1415.              (!(j == 0 && k == (ELEMENTS(colhue) - 2))))) {
  1416.             cnserr = /*MSG47*/"Two primary hues are not adjacent.";
  1417.             return False;
  1418.         }
  1419.  
  1420.         if (Tbit(Red) && Tbit(Purple))
  1421.             j = ELEMENTS(colhue) - 1;
  1422.  
  1423.         hue = (abs(colhue[j].chue) + abs(colhue[k].chue)) * 50L;
  1424.         /* If either is brown, impute saturation and lightness
  1425.            if none was explicitly specified. */
  1426.         if (colhue[j].chue < 0 || colhue[k].chue < 0) {
  1427.             if (lightness == 0)
  1428.                 lightness = BROWNLIGHT;
  1429.             if (saturation == 0)
  1430.                 saturation = BROWNSAT;
  1431.         }
  1432.     } else {
  1433.  
  1434.         /* Case 3.  Quarterway hue specified by one primary hue
  1435.                     and one secondary hue. */
  1436.  
  1437.         for (i = 0; i < ELEMENTS(colhue); i++) {
  1438.             if (tok & colhue[i].cbit) {
  1439.                 j = i;
  1440.                 break;
  1441.             }
  1442.         }
  1443.         for (i = 0; i < ELEMENTS(ishhue); i++) {
  1444.             if (tok & ishhue[i].cbit) {
  1445.                 k = i;
  1446.                 break;
  1447.             }
  1448.         }
  1449.         if ((colhue[j].chue == -colhue[k].chue) || (
  1450.                ((j + 1) != k) && ((j - 1) != k) &&
  1451.                !(j == 0 && k == 2) && !(j == 1 && k == 3) &&
  1452.                !(k == 0 && j == 2) && !(k == 1 && j == 3) &&
  1453.                (!(j == 0 && k == (ELEMENTS(ishhue) - 2))) &&
  1454.                (!(k == 0 && j == (ELEMENTS(ishhue) - 2)))
  1455.               )
  1456.            ) {
  1457.             cnserr = /*MSG48*/"Primary and secondary hues are not adjacent.";
  1458.             return False;
  1459.         }
  1460.  
  1461.         if (Tbit(Red) && Tbit(Purplish))
  1462.             j = ELEMENTS(colhue) - 1;
  1463.         else if (Tbit(Purple) && Tbit(Reddish))
  1464.             k = ELEMENTS(ishhue) - 1;
  1465.  
  1466.         hue = (abs(colhue[j].chue) * 3 + abs(ishhue[k].chue)) * 25L;
  1467.  
  1468.         /* If either is brown, impute saturation and lightness
  1469.            if none was explicitly specified. */
  1470.  
  1471.         if (colhue[j].chue < 0 || ishhue[k].chue < 0) {
  1472.             if (lightness == 0)
  1473.                 lightness = BROWNLIGHT;
  1474.             if (saturation == 0)
  1475.                 saturation = BROWNSAT;
  1476.         }
  1477.     }
  1478.  
  1479.     if (hue < 0) {
  1480.         cnserr = /*MSG49*/"Internal error--cannot determine hue.";
  1481.         return False;
  1482.     }
  1483.  
  1484.     if (lightness == 0)
  1485.         k = defcnslit;
  1486.     else
  1487.         k = litetab[lightness];
  1488.  
  1489.     hsv_rgb(hue / 100.0, satab[saturation] / 10000.0, k / 10000.0,
  1490.             r, g, b);
  1491.     return True;
  1492. }
  1493.  
  1494. /*  CIXNAME  --  Find name of colour vocabulary word from its index.  */
  1495.  
  1496. static char *cixname(cx)
  1497.   colourvocab cx;
  1498. {
  1499.     int i;
  1500.  
  1501.     for (i = 0; i < ELEMENTS(cvocab); i++)
  1502.         if (cvocab[i].ccode == cx)
  1503.             break;
  1504.     return cvocab[i].cname;
  1505. }
  1506.  
  1507. /*  RGB_CNS  --  Find best CNS description for RGB colour expressed
  1508.                  in R, G, and B, from 0 to 1.  */
  1509.  
  1510. static void rgb_cns(r, g, b, cnstr)
  1511.   ads_real r, g, b;
  1512.   char *cnstr;
  1513. {
  1514.     int i, j = 0, k, d, s, v;
  1515.     long lh, ld, hd;
  1516.     ads_real rh, rs, rv;
  1517.  
  1518. #define C(x)  ((char) (x))
  1519. #define CV(x) ((colourvocab) (x))
  1520.  
  1521.     /* Grey scale name table */
  1522.  
  1523.     static struct {
  1524.        int intens;
  1525.        char gname[3];
  1526.     } gtab[] = {
  1527.        {0,     {C(Black),                  0}},
  1528.        {1700,  {C(Very),  C(Dark), C(Gray)  }},
  1529.        {3300,  {C(Dark),  C(Gray),         0}},
  1530.        {5000,  {C(Gray),                   0}},
  1531.        {6700,  {C(Light), C(Gray),         0}},
  1532.        {8300,  {C(Very),  C(Light), C(Gray) }},
  1533.        {10000, {C(White),                  0}}
  1534.       };
  1535.  
  1536.     /* Hue name table */
  1537.  
  1538.     static struct {
  1539.        long huecode;
  1540.        char purename,
  1541.             ishname;
  1542.     } huetab[] = {
  1543.        {0L,     C(Red),    C(Reddish)},
  1544.        {3000L,  C(Orange), C(Orangish)},
  1545.        {6000L,  C(Yellow), C(Yellowish)},
  1546.        {12000L, C(Green),  C(Greenish)},
  1547.        {24000L, C(Blue),   C(Bluish)},
  1548.        {30000L, C(Purple), C(Purplish)},
  1549.        {36000L, C(Red),    C(Reddish)}
  1550.       };
  1551.  
  1552.     /* Chromatic lightness table */
  1553.  
  1554.     static struct {
  1555.        int intens;
  1556.        char lname[2];
  1557.     } ltab[] = {
  1558.        {1250,  {C(Very), C(Dark)  }},
  1559.        {2500,  {C(Dark),         0}},
  1560.        {5000,  {C(Medium),       0}},
  1561.        {7500,  {C(Light),        0}},
  1562.        {10000, {C(Very), C(Light) }}
  1563.       };
  1564.  
  1565.     /* Chromatic saturation table */
  1566.  
  1567.     static struct {
  1568.        int satper;
  1569.        char sname;
  1570.     } stab[] = {
  1571.        {2500,  C(Grayish)  },
  1572.        {5000,  C(Moderate) },
  1573.        {7500,  C(Strong)   },
  1574.        {10000, C(Vivid)    }
  1575.       };
  1576.  
  1577.     cnstr[0] = EOS;
  1578.  
  1579.     rgb_hsv(r, g, b, &rh, &rs, &rv);
  1580.     lh = rh * 100L;
  1581.     s = rs * 10000;
  1582.     v = rv * 10000;
  1583.  
  1584.     if (s == 0) {
  1585.  
  1586.         /* Achromatic */
  1587.  
  1588.         d = 20000;
  1589.         for (i = 0; i < ELEMENTS(gtab); i++) {
  1590.             if (abs(gtab[i].intens - v) < d) {
  1591.                 d = abs(gtab[i].intens - v);
  1592.                 j = i;
  1593.             }
  1594.         }
  1595.         for (i = 0; i < 3; i++) {
  1596.             if (gtab[j].gname[i] == 0)
  1597.                 break;
  1598.             if (strlen(cnstr))
  1599.                 V strcat(cnstr, " ");
  1600.             V strcat(cnstr, cixname(CV(gtab[j].gname[i])));
  1601.         }
  1602.     } else {
  1603.  
  1604.         /* Chromatic.  */
  1605.  
  1606.         /* Locate intensity.   If  the  closest  intensity  is  the
  1607.            default  intensity  in  DEFCNSLIT,  we  don't  edit  any
  1608.            intensity.  You can disable this by setting DEFCNSLIT to
  1609.            -1.  */
  1610.  
  1611.         d = 20000;
  1612.         for (i = 0; i < ELEMENTS(ltab); i++) {
  1613.             if (abs(ltab[i].intens - v) < d) {
  1614.                 d = abs(ltab[i].intens - v);
  1615.                 j = i;
  1616.             }
  1617.         }
  1618.         if (ltab[j].intens != defcnslit) {
  1619.             for (i = 0; i < 2; i++) {
  1620.                 if (ltab[j].lname[i] == 0)
  1621.                     break;
  1622.                 if (strlen(cnstr))
  1623.                     V strcat(cnstr, " ");
  1624.                 V strcat(cnstr, cixname(CV(ltab[j].lname[i])));
  1625.             }
  1626.         }
  1627.  
  1628.         /* Locate saturation.  If the saturation is vivid, nothing
  1629.            is edited. */
  1630.  
  1631.         d = 20000;
  1632.         for (i = 0; i < ELEMENTS(stab); i++) {
  1633.             if (abs(stab[i].satper - s) <= d) {
  1634.                 d = abs(stab[i].satper - s);
  1635.                 j = i;
  1636.             }
  1637.         }
  1638.         if (stab[j].satper != 10000) {
  1639.             if (strlen(cnstr))
  1640.                 V strcat(cnstr, " ");
  1641.             V strcat(cnstr, cixname(CV(stab[j].sname)));
  1642.         }
  1643.  
  1644.         if (strlen(cnstr))
  1645.             V strcat(cnstr, " ");
  1646.  
  1647.         /* Find closest hue name. */
  1648.  
  1649.         ld = 100000L;
  1650.         if (lh == 36000L)
  1651.             lh = 0;
  1652.         for (i = 0; i < ELEMENTS(huetab); i++) {
  1653.             if (abs(huetab[i].huecode - lh) < ld) {
  1654.                 ld = abs(huetab[i].huecode - lh);
  1655.                 j = i;
  1656.             }
  1657.         }
  1658.  
  1659.         /* Now we'll find the next hue in the direction of the
  1660.            actual hue from the specified hue. */
  1661.  
  1662.         if (lh > huetab[j].huecode) {
  1663.             if (j == (ELEMENTS(huetab) - 1))
  1664.                 k = 1;
  1665.             else
  1666.                 k = j + 1;
  1667.         } else {
  1668.             if (j == 0)
  1669.                 k = ELEMENTS(huetab) - 2;
  1670.             else
  1671.                 k = j - 1;
  1672.         }
  1673.  
  1674.         /* Next, compute the distance between the hue and the next
  1675.            neighbour in the hue's direction.  */
  1676.  
  1677.         hd = abs(huetab[j].huecode - huetab[k].huecode);
  1678.  
  1679.         /* The  form of the hue then  depends upon the relationship
  1680.            between the actual distance, D, and the total  distance,
  1681.            HD,  from the closest pure hue, J, and the next pure hue
  1682.            in the direction of the hue supplied,  K.   We  generate
  1683.            the following based upon the relationship:
  1684.  
  1685.                  D / HD          Name
  1686.               ------------     --------
  1687.               0     - 0.125       J
  1688.               0.125 - 0.375     Kish J
  1689.               0.375 - 0.5        J-K
  1690.         */
  1691.  
  1692.         hd = (ld * 10000L) / hd;
  1693.         if (hd < 1250L) {
  1694.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1695.         } else if (hd < 3750L) {
  1696.             V strcat(cnstr, cixname(CV(huetab[k].ishname)));
  1697.             V strcat(cnstr, " ");
  1698.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1699.         } else {
  1700.             V strcat(cnstr, cixname(CV(huetab[j].purename)));
  1701.             V strcat(cnstr, "-");
  1702.             V strcat(cnstr, cixname(CV(huetab[k].purename)));
  1703.         }
  1704.     }
  1705. }
  1706.  
  1707. /*  ACADRGB  --  Takes  an  AutoCAD  colour  number in hsv and returns
  1708.                  red, green, and blue intensities in rgp in the  range
  1709.                  0.0 to 1.0 */
  1710.  
  1711. static void acadrgb(hsv, rgp)
  1712.   int  hsv;
  1713.   struct r_g_b *rgp;
  1714. {
  1715.     static ads_real brightfac[5] = {  /* Brightness levels */
  1716.        1.0, 0.65, 0.5, 0.3, 0.15
  1717.       }, halfsat = .5;                /* Halfway saturation */
  1718.     int ih, vs;
  1719.     ads_real h, s, f, value;
  1720.  
  1721.     assert(hsv > 0 || hsv < 256);
  1722.  
  1723.     switch (hsv) {
  1724.     case BLACK:
  1725.         rgp->red   = 0.0;
  1726.         rgp->blue  = 0.0;
  1727.         rgp->green = 0.0;
  1728.         value = 0.0;
  1729.         break;
  1730.  
  1731.     case RED:
  1732.         rgp->red   = SAT;
  1733.         rgp->green = 0.0;
  1734.         rgp->blue  = 0.0;
  1735.         value = 1.0;
  1736.         break;
  1737.  
  1738.     case YELLOW:
  1739.         rgp->red   = SAT;
  1740.         rgp->green = SAT;
  1741.         rgp->blue  = 0.0;
  1742.         value = 1.0;
  1743.         break;
  1744.  
  1745.     case GREEN:
  1746.         rgp->red   = 0.0;
  1747.         rgp->green = SAT;
  1748.         rgp->blue  = 0.0;
  1749.         value = 1.0;
  1750.         break;
  1751.  
  1752.     case CYAN:
  1753.         rgp->red   = 0.0;
  1754.         rgp->green = SAT;
  1755.         rgp->blue  = SAT;
  1756.         value = 1.0;
  1757.         break;
  1758.  
  1759.     case BLUE:
  1760.         rgp->red   = 0.0;
  1761.         rgp->green = 0.0;
  1762.         rgp->blue  = SAT;
  1763.         value = 1.0;
  1764.         break;
  1765.  
  1766.     case MAGENTA:
  1767.         rgp->red   = SAT;
  1768.         rgp->green = 0.0;
  1769.         rgp->blue  = SAT;
  1770.         value = 1.0;
  1771.         break;
  1772.  
  1773.     case WHITE:
  1774.     case 8:
  1775.     case 9:
  1776.         rgp->red   = SAT;
  1777.         rgp->green = SAT;
  1778.         rgp->blue  = SAT;
  1779.         value = 1.0;
  1780.         break;
  1781.  
  1782.     default:
  1783.  
  1784.         /*  The chromatic colors.  The  hue  resulting  from  an
  1785.             AutoCAD color 10-249 will be determined by its first
  1786.             two digits, and the saturation and  value  from  the
  1787.             last digit, as follows:
  1788.  
  1789.             Hues:
  1790.  
  1791.              10 -- Red
  1792.              50 -- Yellow
  1793.              90 -- Green
  1794.             130 -- Cyan
  1795.             170 -- Blue
  1796.             210 -- Magenta
  1797.  
  1798.             Between  each  of these are three intermediate hues,
  1799.             e.g., between red and yellow, we have:
  1800.  
  1801.              20 -- reddish orange
  1802.              30 -- orange
  1803.              40 -- yellowish orange
  1804.  
  1805.             To each hue number, 0, 2, 4, 6, or 8 can be added to
  1806.             give a different "value", or brightness, with 0  the
  1807.             brightest  and  8  the  weakest.   Finally, 1 can be
  1808.             added to  produce  a  "half-saturated",  or  pastel,
  1809.             color.  For example, color 18 is the dimmest red and
  1810.             10 the brightest red.  19 is the dimmest pink and 11
  1811.             the brightest pink.
  1812.         */
  1813.  
  1814.         if (hsv > 9 && hsv < 250) {
  1815.  
  1816.             /* Apply the algorithm from Foley & van Dam to turn
  1817.                HSV into RGB values */
  1818.  
  1819.             ih = (hsv - 10) / 10;     /* Integer hue value. */
  1820.             if (ih >= 24)             /* Range is 0-23. */
  1821.                 ih -= 24;
  1822.             vs = hsv % 10;            /* Encoded value and saturation */
  1823.             h = ih / 4.;              /* Map into range [0.0,6.0) */
  1824.             ih = h;                   /* The integer part. */
  1825.             f = h - ih;               /* Fractional part. */
  1826.             value = brightfac[vs >> 1]; /* Value in [0,1] */
  1827.             s = vs & 1 ? halfsat : 1.0; /* Saturation */
  1828.  
  1829.             switch (ih) {
  1830.             case 0:
  1831.                 rgp->red   = 1.0;
  1832.                 rgp->green = (ads_real) (1.0 - s * (1.0 - f));
  1833.                 rgp->blue  = (ads_real) (1.0 - s);
  1834.                 break;
  1835.  
  1836.             case 1:
  1837.                 rgp->red   = (ads_real) (1.0 - s * f);
  1838.                 rgp->green = 1.0;
  1839.                 rgp->blue  = (ads_real) (1 - s);
  1840.                 break;
  1841.  
  1842.             case 2:
  1843.                 rgp->red   = (ads_real) (1.0 - s);
  1844.                 rgp->green = 1.0;
  1845.                 rgp->blue  = (ads_real) (1.0 - s *(1.0 - f));
  1846.                 break;
  1847.  
  1848.             case 3:
  1849.                 rgp->red   = (ads_real) (1.0 - s);
  1850.                 rgp->green = (ads_real) (1.0 - s * f);
  1851.                 rgp->blue  = 1.0;
  1852.                 break;
  1853.  
  1854.             case 4:
  1855.                 rgp->red   = (ads_real) (1.0 - s * (1.0 - f));
  1856.                 rgp->green = (ads_real) (1.0 - s);
  1857.                 rgp->blue  = 1.0;
  1858.                 break;
  1859.  
  1860.             case 5:
  1861.                 rgp->red   = 1.0;
  1862.                 rgp->green = (ads_real) (1.0 - s);
  1863.                 rgp->blue  = (ads_real) (1.0 - s * f);
  1864.                 break;
  1865.             }
  1866.         } else {
  1867.             /* Define some extra colours from dark grey to white
  1868.                in the 250 to 255 slots */
  1869.             value = 0.33 + (hsv - 250) * 0.134;
  1870.             rgp->red   = 1.0;
  1871.             rgp->green = 1.0;
  1872.             rgp->blue  = 1.0;
  1873.         }
  1874.         break;                        /* Default */
  1875.     }
  1876.     rgp->red   *= value;              /* Apply lightness scale factor */
  1877.     rgp->green *= value;              /* to components resulting from */
  1878.     rgp->blue  *= value;              /* hue and saturation. */
  1879. }
  1880.  
  1881. /*  RGBACAD  --  Find the AutoCAD colour closest to in RGB space to a
  1882.                  specified RGB triple.  */
  1883.  
  1884. static int rgbacad(r, g, b)
  1885.   ads_real r, g, b;
  1886. {
  1887.     int i, low, ccol;
  1888.     ads_real closest = 1000.0;
  1889.     struct r_g_b rc;
  1890.  
  1891.     assert(r >= 0.0 && r <= 1.0);
  1892.     assert(g >= 0.0 && g <= 1.0);
  1893.     assert(b >= 0.0 && b <= 1.0);
  1894.  
  1895.     /* If we're mapping to the 8 colour gamut, turn all grey scale
  1896.        colours into white and map the rest based on hue alone. */
  1897.  
  1898.     if (gamut == 8) {
  1899.         ads_real h, s, v;
  1900.  
  1901.         rgb_hsv(r, g, b, &h, &s, &v);
  1902.         return s == 0.0 ? WHITE :
  1903.                (RED + ((((int) (h + 30.0)) % 360) / 60));
  1904.     }
  1905.  
  1906.     /* Note  that we start with  colour 1 since 0 (black) is not a
  1907.        valid user-specified colour.  If this is a grey scale tone,
  1908.        map only to AutoCAD's grey scale indices.  */
  1909.  
  1910.     ccol = low = (r == g && r == b) ? 250 : 1;
  1911.  
  1912.     for (i = low; i < 256; i++) {
  1913.         ads_real cdist;
  1914.  
  1915.         acadrgb(i, &rc);
  1916.         rc.red -= r;
  1917.         rc.green -= g;
  1918.         rc.blue -= b;
  1919.         cdist = rc.red * rc.red + rc.green * rc.green +
  1920.                 rc.blue * rc.blue;
  1921.         if (cdist < closest) {
  1922.             ccol = i;
  1923.             if ((closest = cdist) == 0.0)
  1924.                 break;
  1925.         }
  1926.     }
  1927.     if (ccol == 255)                  /* If synonym for white... */
  1928.         ccol = 7;                     /* ...make simple white. */
  1929.     return ccol;
  1930. }
  1931.  
  1932. /*  RETRGB  --  Return an RGB triple as either an RGB point or
  1933.                 the closest AutoCAD standard colour.  */
  1934.  
  1935. static void retrgb(acad, r, g, b)
  1936.   Boolean acad;
  1937.   ads_real r, g, b;
  1938. {
  1939.     if (acad) {
  1940.         ads_retint(rgbacad(r, g, b));
  1941.     } else {
  1942.         ads_point p;
  1943.  
  1944.         Spoint(p, r, g, b);
  1945.         ads_retpoint(p);
  1946.     }
  1947. }
  1948.  
  1949. /*  TRIPLE  --  Scan  a  triple  of  real  arguments  into an array of
  1950.                 reals.  Integers are accepted and converted to  reals.
  1951.                 True  is  returned  if  valid  arguments are obtained;
  1952.                 False otherwise.  */
  1953.  
  1954. static Boolean triple(cdesc, rangecheck)
  1955.   ads_real cdesc[3];
  1956.   Boolean rangecheck;
  1957. {
  1958.     int nargs;
  1959.     struct resbuf *rb1 = ads_getargs();
  1960.  
  1961.     ads_retnil();
  1962.     for (nargs = 0; nargs < 3; nargs++) {
  1963.         if (rb1 == NULL)
  1964.             break;
  1965.         if (rb1->restype == RTSHORT) {
  1966.             cdesc[nargs] = rb1->resval.rint;
  1967.         } else if (rb1->restype == RTREAL) {
  1968.             cdesc[nargs] = rb1->resval.rreal;
  1969.         } else if (nargs == 0 && rb1->restype == RT3DPOINT) {
  1970.             Cpoint(cdesc, rb1->resval.rpoint);
  1971.             nargs = 2;
  1972.         } else {
  1973.             ads_fail(/*MSG50*/"incorrect argument type");
  1974.             return False;
  1975.         }
  1976.         rb1 = rb1->rbnext;
  1977.     }
  1978.  
  1979.     /* Make sure there were enough arguments. */
  1980.  
  1981.     if (nargs < 3) {
  1982.         ads_fail(/*MSG51*/"too few arguments");
  1983.         return False;
  1984.     }
  1985.  
  1986.     /* Make sure there are no more arguments. */
  1987.  
  1988.     if (rb1 != NULL) {
  1989.         ads_fail(/*MSG52*/"too many arguments");
  1990.         return False;
  1991.     }
  1992.  
  1993.     /* Range check arguments if requested. */
  1994.  
  1995.     if (rangecheck) {
  1996.         for (nargs = 0; nargs < 3; nargs++) {
  1997.             if (rangecheck && (cdesc[nargs] < 0.0 || cdesc[nargs] > 1.0)) {
  1998.                 ads_fail(/*MSG53*/"argument out of range");
  1999.                 return False;
  2000.             }
  2001.         }
  2002.     }
  2003.  
  2004.     return True;
  2005. }
  2006.  
  2007. /*  CMY  --  Specify colour as CMY triple.  */
  2008.  
  2009. static void cmy(acad)
  2010.   Boolean acad;
  2011. {
  2012.     ads_real cdesc[3];
  2013.  
  2014.     if (triple(cdesc, True)) {
  2015.         retrgb(acad, 1.0 - cdesc[0], 1.0 - cdesc[1],
  2016.                1.0 - cdesc[2]);
  2017.     }
  2018. }
  2019.  
  2020. /*  CTEMP  --  Specify colour as a colour temperature.  */
  2021.  
  2022. static void ctemp(acad)
  2023.   Boolean acad;
  2024. {
  2025.     struct resbuf *rb;
  2026.  
  2027.     ads_retnil();
  2028.  
  2029.     if ((rb = ads_getargs()) == NULL) {
  2030.         ads_fail(/*MSG63*/"too few arguments");
  2031.     } else {
  2032.         ads_real degrees, ir, ig, ib;
  2033.  
  2034.         if (rb->restype == RTSHORT) {
  2035.             degrees = rb->resval.rint;
  2036.         } else if (rb->restype == RTREAL) {
  2037.             degrees = rb->resval.rreal;
  2038.         } else {
  2039.             ads_fail(/*MSG64*/"incorrect argument type");
  2040.             return;
  2041.         }
  2042.  
  2043.         /* Make sure there are no more arguments. */
  2044.  
  2045.         if (rb->rbnext != NULL) {
  2046.             ads_fail(/*MSG65*/"too many arguments");
  2047.             return;
  2048.         }
  2049.  
  2050.         ctemp_rgb(degrees, &ir, &ig, &ib);
  2051.         retrgb(acad, ir, ig, ib);
  2052.     }
  2053. }
  2054.  
  2055. /*  CNS  --  Specify colour as a CNS string.  */
  2056.  
  2057. static void cns(acad)
  2058.   Boolean acad;
  2059. {
  2060.     struct resbuf *rb;
  2061.  
  2062.     ads_retnil();
  2063.  
  2064.     if ((rb = ads_getargs()) == NULL) {
  2065.         ads_fail(/*MSG54*/"too few arguments");
  2066.         return;
  2067.     } else {
  2068.         struct resbuf *rb1 = rb;
  2069.         ads_real ir, ig, ib;
  2070.  
  2071.         if (rb1->restype != RTSTR) {
  2072.             ads_fail(/*MSG55*/"incorrect argument type");
  2073.             return;
  2074.         }
  2075.  
  2076.         /* Make sure there are no more arguments. */
  2077.  
  2078.         if (rb1->rbnext != NULL) {
  2079.             ads_fail(/*MSG56*/"too many arguments");
  2080.             return;
  2081.         }
  2082.  
  2083.         if (cns_rgb(rb1->resval.rstring, &ir, &ig, &ib)) {
  2084.             retrgb(acad, ir, ig, ib);
  2085.         }
  2086.     }
  2087. }
  2088.  
  2089. /*  CNSER  --  Return string describing last CNS error, if any.  */
  2090.  
  2091. static void cnser()
  2092. {
  2093.     if (cnserr == NULL)
  2094.         ads_retnil();
  2095.     else
  2096.         ads_retstr(cnserr);
  2097. }
  2098.  
  2099. /*  HLS  --  Specify colour as HLS triple.  */
  2100.  
  2101. static void hls(acad)
  2102.   Boolean acad;
  2103. {
  2104.     ads_real cdesc[3];
  2105.  
  2106.     if (triple(cdesc, True)) {
  2107.         ads_real ir, ig, ib;
  2108.  
  2109.         hls_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
  2110.         retrgb(acad, ir, ig, ib);
  2111.     }
  2112. }
  2113.  
  2114. /*  HSV  --  Specify colour as HSV triple.  */
  2115.  
  2116. static void hsv(acad)
  2117.   Boolean acad;
  2118. {
  2119.     ads_real cdesc[3];
  2120.  
  2121.     if (triple(cdesc, True)) {
  2122.         ads_real ir, ig, ib;
  2123.  
  2124.         hsv_rgb(cdesc[0] * 360.0, cdesc[1], cdesc[2], &ir, &ig, &ib);
  2125.         retrgb(acad, ir, ig, ib);
  2126.     }
  2127. }
  2128.  
  2129. /*  RGB  --  Specify colour as RGB triple.  */
  2130.  
  2131. static void rgb(acad)
  2132.   Boolean acad;
  2133. {
  2134.     ads_real cdesc[3];
  2135.  
  2136.     if (triple(cdesc, True)) {
  2137.         retrgb(acad, cdesc[0], cdesc[1], cdesc[2]);
  2138.     }
  2139. }
  2140.  
  2141. /*  YIQ  --  Specify colour as YIQ triple.  */
  2142.  
  2143. static void yiq(acad)
  2144.   Boolean acad;
  2145. {
  2146.     ads_real cdesc[3];
  2147.  
  2148.     if (triple(cdesc, False)) {
  2149.         ads_real ir, ig, ib;
  2150.  
  2151.         if ((cdesc[0] < 0.0 || cdesc[0] > 1.0) &&
  2152.             (cdesc[1] < -0.6 || cdesc[0] > 0.6) &&
  2153.             (cdesc[2] < -0.52 || cdesc[2] > 0.52)) {
  2154.             ads_fail(/*MSG57*/"argument out of range");
  2155.         }
  2156.  
  2157.         yiq_rgb(cdesc[0], cdesc[1], cdesc[2], &ir, &ig, &ib);
  2158.  
  2159.         retrgb(acad, ir, ig, ib);
  2160.     }
  2161. }
  2162.  
  2163. /*  Colour system to AutoCAD colour functions. */
  2164.  
  2165. static void cmyac()   { cmy(True);   }
  2166. static void ctempac() { ctemp(True); }
  2167. static void yiqac()   { yiq(True);   }
  2168. static void hsvac()   { hsv(True);   }
  2169. static void rgbac()   { rgb(True);   }
  2170. static void hlsac()   { hls(True);   }
  2171. static void cnsac()   { cns(True);   }
  2172.  
  2173. /*  Colour system to RGB functions.  */
  2174.  
  2175. static void cmyrgb()   { cmy(False);   }
  2176. static void ctemprgb() { ctemp(False); }
  2177. static void yiqrgb()   { yiq(False);   }
  2178. static void hsvrgb()   { hsv(False);   }
  2179. static void hlsrgb()   { hls(False);   }
  2180. static void cnsrgb()   { cns(False);   }
  2181.  
  2182. /*  ACADCOL  --  Obtain AutoCAD colour.  We accept any of the following:
  2183.  
  2184.     1.  A single integer, representing an AutoCAD standard colour index.
  2185.     2.  A triple of reals and/or integers, representing RGB intensities.
  2186.     3.  A list of three reals and/or integers, representing RGB intensities.
  2187. */
  2188.  
  2189. static Boolean acadcol(rp)
  2190.   struct r_g_b *rp;
  2191. {
  2192.     ads_real crgb[3];
  2193.     struct resbuf *rb = ads_getargs();
  2194.  
  2195.     ads_retnil();
  2196.  
  2197.     if (rb == NULL) {
  2198.         ads_fail(/*MSG58*/"too few arguments");
  2199.         return False;
  2200.     }
  2201.  
  2202.     if ((rb->restype == RTSHORT) && (rb->rbnext == NULL)) {
  2203.         int cindex = rb->resval.rint;
  2204.  
  2205.         if (cindex < 0 || cindex > 255) {
  2206.             ads_fail(/*MSG59*/"argument out of range");
  2207.             return False;
  2208.         }
  2209.         acadrgb(cindex, rp);
  2210.         return True;
  2211.     }
  2212.  
  2213.     if (triple(crgb, True)) {
  2214.         rp->red   = crgb[0];
  2215.         rp->green = crgb[1];
  2216.         rp->blue  = crgb[2];
  2217.     } else {
  2218.         return False;
  2219.     }
  2220.  
  2221.     return True;
  2222. }
  2223.  
  2224. /*  TORGB  --  Convert internal colour to RGB triple.  */
  2225.  
  2226. static void torgb()
  2227. {
  2228.     struct r_g_b rc;
  2229.  
  2230.     if (acadcol(&rc)) {
  2231.         ads_point p;
  2232.  
  2233.         Spoint(p, rc.red, rc.green, rc.blue);
  2234.         ads_retpoint(p);
  2235.     }
  2236. }
  2237.  
  2238. /*  TOCMY  --  Convert internal colour to CMY triple.  */
  2239.  
  2240. static void tocmy()
  2241. {
  2242.     struct r_g_b rc;
  2243.  
  2244.     if (acadcol(&rc)) {
  2245.         ads_point p;
  2246.  
  2247.         rgb_cmy(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2248.         ads_retpoint(p);
  2249.     }
  2250. }
  2251.  
  2252. /*  TOYIQ  --  Convert internal colour to YIQ triple.  */
  2253.  
  2254. static void toyiq()
  2255. {
  2256.     struct r_g_b rc;
  2257.  
  2258.     if (acadcol(&rc)) {
  2259.         ads_point p;
  2260.  
  2261.         rgb_yiq(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2262.         ads_retpoint(p);
  2263.     }
  2264. }
  2265.  
  2266. /*  TOHSV  --  Convert internal colour to HSV triple.  */
  2267.  
  2268. static void tohsv()
  2269. {
  2270.     struct r_g_b rc;
  2271.  
  2272.     if (acadcol(&rc)) {
  2273.         ads_point p;
  2274.  
  2275.         rgb_hsv(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2276.         p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
  2277.         ads_retpoint(p);
  2278.     }
  2279. }
  2280.  
  2281. /*  TOHLS  --  Convert internal colour to HLS triple.  */
  2282.  
  2283. static void tohls()
  2284. {
  2285.     struct r_g_b rc;
  2286.  
  2287.     if (acadcol(&rc)) {
  2288.         ads_point p;
  2289.  
  2290.         rgb_hls(rc.red, rc.green, rc.blue, &p[X], &p[Y], &p[Z]);
  2291.         p[X] = (p[X] < 0.0) ? 0.0 : (p[X] / 360.0);
  2292.         ads_retpoint(p);
  2293.     }
  2294. }
  2295.  
  2296. /*  TOCNS  --  Convert internal colour to CNS string.  */
  2297.  
  2298. static void tocns()
  2299. {
  2300.     struct r_g_b rc;
  2301.  
  2302.     if (acadcol(&rc)) {
  2303.         char cnstr[40];
  2304.  
  2305.         rgb_cns(rc.red, rc.green, rc.blue, cnstr);
  2306.         ads_retstr(cnstr);
  2307.     }
  2308. }
  2309.  
  2310. /*  COLSET  --  Set colour gamut available.  */
  2311.  
  2312. static void colset()
  2313. {
  2314.     struct resbuf *rb = ads_getargs();
  2315.  
  2316.     ads_retnil();
  2317.  
  2318.     if (rb == NULL) {
  2319.         ads_retint(gamut);
  2320.         return;
  2321.     }
  2322.  
  2323.     if (rb->rbnext != NULL) {
  2324.         ads_fail(/*MSG60*/"too many arguments");
  2325.         return;
  2326.     }
  2327.  
  2328.     if (rb->restype == RTSHORT) {
  2329.         int colsys = rb->resval.rint;
  2330.  
  2331.         switch (colsys) {
  2332.         case 8:
  2333.         case 256:
  2334.             gamut = colsys;
  2335.             ads_retint(gamut);
  2336.             break;
  2337.  
  2338.         default:
  2339.             ads_fail(/*MSG61*/"argument out of range");
  2340.         }
  2341.         return;
  2342.     }
  2343.     ads_fail(/*MSG62*/"incorrect argument type");
  2344. }
  2345.